﻿namespace WinRT.Triggers
{
    #region Using directives

    using Windows.UI.Xaml;

    #endregion

    /// <summary>
    /// A <see cref="Trigger"/> that responds to an event on the associated <see cref="FrameworkElement"/>.
    /// </summary>
    public class EventTrigger : EventHookingTrigger
    {
        #region Static Fields

        /// <summary>
        /// The EventName dependency property of type <see cref="string"/>.
        /// </summary>
        public static readonly DependencyProperty EventNameProperty = DependencyProperty.Register(
            "EventName", typeof(string), typeof(EventTrigger), new PropertyMetadata(DependencyProperty.UnsetValue));

        /// <summary>
        /// The SourceObject property of type <see cref="object"/>. If this is unset or set to null then the <see cref="FrameworkElement"/> 
        /// that the trigger is attached to will be treated as the source object.
        /// </summary>
        public static readonly DependencyProperty SourceObjectProperty =
            DependencyProperty.Register("SourceObject", typeof(object), typeof(EventTrigger), new PropertyMetadata(DependencyProperty.UnsetValue, SourceObjectPropertyChanged));

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets the name of the event that the trigger should respond to.
        /// </summary>
        public string EventName
        {
            get
            {
                return (string)this.GetValue(EventNameProperty);
            }

            set
            {
                this.SetValue(EventNameProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the source object that the event is defined on. If this is null 
        /// then the <see cref="FrameworkElement"/> that the trigger is attached to will be 
        /// treated as the source object.
        /// </summary>
        public object SourceObject
        {
            get { return this.GetValue(SourceObjectProperty); }
            set { this.SetValue(SourceObjectProperty, value); }
        }

        #endregion

        #region Public Methods and Operators

        /// <inheritdoc />
        public override void Attach(FrameworkElement obj)
        {
            base.Attach(obj);

            this.HookEvent(this.EventName, this.SourceObject);
        }

        /// <inheritdoc />
        public override void Detach()
        {
            base.Detach();

            this.UnhookEvent(this.SourceObject);
        }

        #endregion

        #region Methods

        /// <summary>
        /// Called when the <see cref="SourceObject"/> property changes.
        /// </summary>
        /// <param name="d">
        /// The dependency object associated to the raised event.
        /// </param>
        /// <param name="e">
        /// The event arguments.
        /// </param>
        private static void SourceObjectPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var trigger = d as EventTrigger;
            if (trigger != null)
            {
                trigger.UnhookEvent(e.OldValue);
                trigger.HookEvent(trigger.EventName, e.NewValue);
            }
        }

        #endregion
    }
}